package com.chinatechstar.component.commons.utils;

import com.chinatechstar.component.commons.exception.AjaxExceptionEnum;
import net.logstash.logback.encoder.org.apache.commons.lang3.time.DateFormatUtils;

import java.sql.Time;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;
import java.util.regex.Pattern;

/**
 * 时间工具类
 *
 * @author Rei
 */
public class DateUtils {
    public static final String DEFAULT_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String DEFAULT_YMD_FORMAT = "yyyy-MM-dd";
    public static final String DEFAULT_TIMESTAMP_FORMAT = "yyyy-mm-dd hh:mm:ss[.fffffffff]";
    public static final String EXCEL_DAILY_PROD_FORMAT = "yyyy/M/d";
    public static final String EXCEL_TRACK_FORMAT = "yyyy.M.d";
    public static final String SHEET_NAME_FORMAT = "M.d";
    public static final String DIR_FORMAT = "yyyyMMddHHmmss";
    public static final String YEAR_FORMAT = "yyyy";
    public static final String A2_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ssXXX";
    public static final String EXCEL_CONSTR_TIME_FORMAT = "HH:mm:ss";

    public static final String REGEX_HHmm = "([0-1]?[0-9]|2[0-3]):([0-5][0-9])$";
    public static final String REGEX_HHmmss = "([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$";

    /**
     * localDate转date
     *
     * @param localDate localDate
     * @return Date
     */
    public static Date asDate(LocalDate localDate) {
        return Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * localDateTime转date
     *
     * @param localDateTime localDateTime
     * @return Date
     */
    public static Date asDate(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 字符串日期转Date
     *
     * @param str    字符串日期
     * @param format 字符串日期格式
     * @return Date
     */
    public static Date strDate2Date(String str, String format) {
        DateFormat fmt = new SimpleDateFormat(format);
        try {
            return fmt.parse(str);
        } catch (ParseException e) {
            throw new IllegalArgumentException(AjaxExceptionEnum.DATE_IS_INVALID.getMsg());
        }
    }

    /**
     * java.util.Date转java.sql.Date
     *
     * @param date date
     * @return java.sql.Date
     */
    public static java.sql.Date asSqlDate(Date date) {
        return java.sql.Date.valueOf(asLocalDate(date));
    }

    /**
     * localDate转java.sql.Date
     *
     * @param date date
     * @return java.sql.Date
     */
    public static java.sql.Date asSqlDate(LocalDate date) {
        return java.sql.Date.valueOf(date);
    }

    /**
     * 字符串日期转java.sql.Date
     *
     * @param str    字符串日期
     * @param format 字符串日期格式
     * @return Date
     */
    public static java.sql.Date strDate2SqlDate(String str, String format) {
        DateFormat fmt = new SimpleDateFormat(format);
        try {
            Date d = fmt.parse(str);
            return new java.sql.Date(d.getTime());
        } catch (ParseException e) {
            throw new IllegalArgumentException(AjaxExceptionEnum.DATE_IS_INVALID.getMsg());
        }
    }

    /**
     * 字符串时间转Date
     *
     * @param str    字符串时间
     * @param format 字符串时间格式
     * @return Date
     */
    public static java.sql.Time strTime2SqlTime(String str, String format) {
        SimpleDateFormat fmt = new SimpleDateFormat(format);
        try {
            fmt.parse(str);
            return Time.valueOf(str);
        } catch (ParseException e) {
            throw new IllegalArgumentException(AjaxExceptionEnum.TIME_IS_INVALID.getMsg());
        }
    }

    /**
     * date转localDate
     *
     * @param date date
     * @return LocalDate
     */
    public static LocalDate asLocalDate(Date date) {
        return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDate();
    }

    /**
     * 字符串日期转localDate
     *
     * @param str    字符串日期
     * @param format 字符串日期格式
     * @return LocalDate
     */
    public static LocalDate strDate2LocalDate(String str, String format) {
        return LocalDate.parse(str, DateTimeFormatter.ofPattern(format));
    }

    /**
     * date转localDateTime
     *
     * @param date date
     * @return localDateTime
     */
    public static LocalDateTime asLocalDateTime(Date date) {
        return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime();
    }

    /**
     * 字符串日期转localDateTime
     *
     * @param str    字符串日期
     * @param format 字符串日期格式
     * @return localDateTime
     */
    public static LocalDateTime strTime2LocalDateTime(String str, String format) {
        return LocalDateTime.parse(str, DateTimeFormatter.ofPattern(format));
    }

    /**
     * 时间戳转localDateTime
     *
     * @param timestamp 时间戳
     * @return LocalDate
     */
    public static LocalDateTime asLocalDateTime(Timestamp timestamp) {
        return LocalDateTime.ofInstant(timestamp.toInstant(), ZoneId.systemDefault());
    }

    /**
     * long时间转localDateTime
     *
     * @param time long时间
     * @return LocalDateTime
     */
    public static LocalDateTime asLocalDateTime(Long time) {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneId.systemDefault());
    }

    /**
     * 时间戳string转Timestamp
     *
     * @param timestamp 时间戳字符串
     * @return Timestamp
     */
    public static Timestamp asTimestamp(String timestamp) {
        return new Timestamp(Long.parseLong(timestamp));
    }

    /**
     * localDate转Timestamp
     *
     * @param localDate localDate
     * @return Timestamp
     */
    public static Timestamp asTimestamp(LocalDate localDate) {
        return Timestamp.valueOf(localDate.atStartOfDay());
    }

    /**
     * localDateTime转Timestamp
     *
     * @param localDateTime localDateTime
     * @return Timestamp
     */
    public static Timestamp asTimestamp(LocalDateTime localDateTime) {
        return Timestamp.valueOf(localDateTime);
    }

    /**
     * date转Timestamp
     *
     * @param date 日期
     * @return Timestamp
     */
    public static Timestamp asTimestamp(Date date) {
        return new Timestamp(date.getTime());
    }

    /**
     * 字符串日期（yyyy-MM-dd）转Timestamp
     *
     * @param str    字符串日期
     * @param format 字符串日期格式
     * @return Timestamp
     */
    public static Timestamp strDate2Timestamp(String str, String format) {
        LocalDate localDate = strDate2LocalDate(str, format);
        return asTimestamp(localDate);
    }

    /**
     * 字符串日期（yyyy-MM-dd HH:mm:ss）转Timestamp
     *
     * @param str    字符串日期
     * @param format 字符串日期格式
     * @return Timestamp
     */
    public static Timestamp strTime2Timestamp(String str, String format) {
        LocalDateTime localDateTime = strTime2LocalDateTime(str, format);
        return asTimestamp(localDateTime);
    }

    /**
     * 时间戳转字符串日期
     *
     * @param timestamp 时间戳
     * @param format    字符串日期格式
     * @return String
     */
    public static String timestamp2Str(Timestamp timestamp, String format) {
        return asLocalDateTime(timestamp).format(DateTimeFormatter.ofPattern(format));
    }

    /**
     * localDate转字符串日期
     *
     * @param localDate localDate
     * @param format    字符串日期格式
     * @return String
     */
    public static String localDate2Str(LocalDate localDate, String format) {
        return localDate.format(DateTimeFormatter.ofPattern(format));
    }

    /**
     * localDateTime转字符串日期
     *
     * @param localDateTime localDateTime
     * @param format        字符串日期格式
     * @return String
     */
    public static String localDateTime2Str(LocalDateTime localDateTime, String format) {
        return localDateTime.format(DateTimeFormatter.ofPattern(format));
    }

    /**
     * date转字符串日期
     *
     * @param date   date
     * @param format 字符串日期格式
     * @return String
     */
    public static String date2Str(Date date, String format) {
        return DateFormatUtils.format(date, format);
    }


    /**
     * 比较第一个日期是否小于第二个日期
     *
     * @param firstDate  第一个日期
     * @param secondDate 第二个日期
     * @return true-小于;false-大于
     */
    public static boolean localDateIsBefore(LocalDate firstDate, LocalDate secondDate) {
        return firstDate.isBefore(secondDate);
    }


    /**
     * 比较第一个日期是否大于第二个日期
     *
     * @param firstDate  第一个日期
     * @param secondDate 第二个日期
     * @return true-大于;false-不大于
     */
    public static boolean localDateIsAfter(LocalDate firstDate, LocalDate secondDate) {
        return firstDate.isAfter(secondDate);
    }

    /**
     * 比较两个日期是否相等
     *
     * @param firstDate  第一个日期
     * @param secondDate 第二个日期
     * @return true-相等;false-不相等
     */
    public static boolean localDateIsEqual(LocalDate firstDate, LocalDate secondDate) {
        return firstDate.isEqual(secondDate);
    }

    /**
     * 比较两个日期是否相等（只比较日期）
     *
     * @param firstDate  第一个日期
     * @param secondDate 第二个日期
     * @return true-相等;false-不相等
     */
    public static boolean dateIsEqual(Date firstDate, Date secondDate) {
        return localDateIsEqual(asLocalDate(firstDate), asLocalDate(secondDate));
    }

    /**
     * 判断日期是否在指定日期区间，默认闭区间
     * 0: [date Start, date End] | 1: (date Start, date End) | 2:(date Start, date End ] | 3 :[date Start, date End)
     *
     * @param dateStart 开始时间
     * @param dateEnd   结束时间
     * @param data      指定时间
     * @return boolean
     **/
    public static boolean isContainDate(LocalDate dateStart, LocalDate dateEnd, String... data) {
        boolean b = false;
        final LocalDate planDate = LocalDate.parse(data[0]);
        String interval = data.length > 1 ? data[1] : "0";
        switch (interval) {
            case "0": {
                b = (planDate.isAfter(dateStart) && planDate.isBefore(dateEnd)) || planDate.isEqual(dateEnd) || planDate.isEqual(dateStart);
            }
            break;
            case "1": {
                b = (planDate.isAfter(dateStart) && planDate.isBefore(dateEnd));
            }
            break;
            case "2": {
                b = (planDate.isAfter(dateStart) && planDate.isBefore(dateEnd)) || planDate.isEqual(dateEnd);
            }
            break;
            case "3": {
                b = (planDate.isAfter(dateStart) && planDate.isBefore(dateEnd)) || planDate.isEqual(dateStart);
            }
            break;
            default:
                break;
        }
        return b;
    }

    /**
     * 取本年第一天
     *
     * @param date 日期
     * @return LocalDate
     */
    public static LocalDate firstDayOfThisYear(LocalDate date) {
        return date.with(TemporalAdjusters.firstDayOfYear());
    }

    /**
     * 取本年最后一天
     *
     * @param date 日期
     * @return LocalDate
     */
    public static LocalDate lastDayOfThisYear(LocalDate date) {
        return date.with(TemporalAdjusters.lastDayOfYear());
    }

    /**
     * 取本月第一天
     *
     * @return LocalDate
     */
    public static LocalDate firstDayOfThisMonth() {
        LocalDate today = LocalDate.now();
        return today.with(TemporalAdjusters.firstDayOfMonth());
    }

    /**
     * 取本月第N天
     *
     * @param n 天数
     * @return LocalDate
     */
    public static LocalDate dayOfThisMonth(int n) {
        LocalDate today = LocalDate.now();
        return today.withDayOfMonth(n);
    }

    /**
     * 取本月最后一天
     *
     * @return LocalDate
     */
    public static LocalDate lastDayOfThisMonth() {
        LocalDate today = LocalDate.now();
        return today.with(TemporalAdjusters.lastDayOfMonth());
    }

    /**
     * 取本月第一天的开始时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime startOfThisMonth() {
        return LocalDateTime.of(firstDayOfThisMonth(), LocalTime.MIN);
    }


    /**
     * 取本月最后一天的结束时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime endOfThisMonth() {
        return LocalDateTime.of(lastDayOfThisMonth(), LocalTime.MAX);
    }

    /**
     * 获取年份
     *
     * @param date 日期
     * @return int
     */
    public static int getYear(Date date) {
        LocalDate localDate = asLocalDate(date);
        return localDate.getYear();
    }

    /**
     * 获取年份
     *
     * @param date Timestamp日期
     * @return int
     */
    public static int getYear(Timestamp date) {
        LocalDate localDate = asLocalDate(date);
        return localDate.getYear();
    }

    /**
     * 获取年份
     *
     * @param date 日期
     * @return int
     */
    public static String getYear(String date, String format) {
        try {
            LocalDate localDate = strDate2LocalDate(date, format);
            return String.valueOf(localDate.getYear());
        } catch (Exception e) {
            return null;
        }
    }


    /**
     * 比较当年和传入年份是否相等
     *
     * @param year 年份 String
     * @return true-相等;false-不相等
     */
    public static boolean yearIsEqual(String year) {
        return year.equals(getCurrStrYear());
    }

    /**
     * 比较当年和传入年份是否相等
     *
     * @param year 年份 Int
     * @return true-相等;false-不相等
     */
    public static boolean yearIsEqual(int year) {
        return year == getCurrIntYear();
    }

    /**
     * 获取当年年份
     *
     * @return String
     */
    public static String getCurrStrYear() {
        return DateFormatUtils.format(new Date(), YEAR_FORMAT);
    }

    /**
     * 获取当年年份
     *
     * @return int
     */
    public static int getCurrIntYear() {
        return asLocalDate(new Date()).getYear();
    }

    /**
     * 合并年月日与时分秒
     *
     * @param date java.util.Date
     * @param time java.sql.Time
     * @return Timestamp
     */
    public static Timestamp mergeDateAndTime(Date date, Time time) {
        return asTimestamp(LocalDateTime.of(asLocalDate(date), time.toLocalTime()));
    }

    /**
     * 合并年月日与时分秒
     *
     * @param date java.sql.Date
     * @param time java.sql.Time
     * @return Timestamp
     */
    public static Timestamp mergeDateAndTime(java.sql.Date date, Time time) {
        return asTimestamp(LocalDateTime.of(date.toLocalDate(), time.toLocalTime()));
    }

    /**
     * 获取两个日期之间的差值
     *
     * @param firstDate  日期1
     * @param secondDate 日期2
     * @return long
     */
    public static long getPeriodOfLocalDate(LocalDate firstDate, LocalDate secondDate) {
        long until = firstDate.until(secondDate, ChronoUnit.DAYS);
        return Math.abs(until) + 1;
    }

    /**
     * 获取两个日期之间的差值（只比较日期）
     *
     * @param firstDate  日期1
     * @param secondDate 日期2
     * @return long
     */
    public static long getPeriodOfDate(Date firstDate, Date secondDate) {
        long until = asLocalDate(firstDate).until(asLocalDate(secondDate), ChronoUnit.DAYS);
        return Math.abs(until) + 1;
    }

    /**
     * 时间格式判断
     *
     * @param time  字符串时间
     * @param regex 正则表达式
     * @return boolean
     */
    public static boolean timeRegex(String time, String regex) {
        return Pattern.matches(regex, time);
    }

    /**
     * 秒转换小时-分-秒
     *
     * @param seconds 秒为单位 比如..600秒
     * @return HH:mm:ss
     */
    public static String secToTime(int seconds) {
        int hour = seconds / 3600;
        int minute = (seconds - hour * 3600) / 60;
        int second = (seconds - hour * 3600 - minute * 60);

        StringBuilder sb = new StringBuilder();
        if (second == 0 || second == 86400) {
            sb.append("00:00:00");
        } else {
            if (hour > 0) {
                sb.append(unitFormat(hour)).append(":");
            } else {
                sb.append("00:");
            }
            if (minute > 0) {
                sb.append(unitFormat(minute)).append(":");
            } else {
                sb.append("00:");
            }
            if (second > 0) {
                sb.append(unitFormat(second));
            }
        }
        return sb.toString();
    }

    /**
     * 将int类型数字转换成时分秒毫秒的格式数据
     *
     * @param time long类型的数据
     * @return HH:mm:ss.SSS
     */
    public static String msecToTime(int time) {
        String timeStr;
        int hour;
        int minute;
        int second;
        int millisecond;
        if (time <= 0) {
            return "00:00:00.000";
        } else {
            second = time / 1000;
            minute = second / 60;
            millisecond = time % 1000;
            if (second < 60) {
                timeStr = "00:00:" + unitFormat(second) + "." + unitFormat2(millisecond);
            } else if (minute < 60) {
                second = second % 60;
                timeStr = "00:" + unitFormat(minute) + ":" + unitFormat(second) + "." + unitFormat2(millisecond);
            } else {
                // 数字>=3600 000的时候
                hour = minute / 60;
                minute = minute % 60;
                second = second - hour * 3600 - minute * 60;
                timeStr = unitFormat(hour) + ":" + unitFormat(minute) + ":" + unitFormat(second) + "."
                        + unitFormat2(millisecond);
            }
        }
        return timeStr;
    }

    /**
     * 时分秒的格式转换
     *
     * @param i 数字
     * @return String
     */
    public static String unitFormat(int i) {
        String retStr;
        if (i >= 0 && i < 10) {
            retStr = "0" + i;
        } else {
            retStr = "" + i;
        }

        return retStr;
    }

    /**
     * 毫秒的格式转换
     *
     * @param i 数字
     * @return String
     */
    public static String unitFormat2(int i) {
        String retStr;
        if (i >= 0 && i < 10) {
            retStr = "00" + i;
        } else if (i >= 10 && i < 100) {
            retStr = "0" + i;
        } else {
            retStr = "" + i;
        }
        return retStr;
    }

    /**
     * 获取当天的0点0时0分
     *
     * @return Timestamp
     */
    public static Timestamp getInitToday() {
        // 获取当前时间
        String timestamp = DateFormatUtils.format(new Date(), "yyyy-MM-dd 00:00:00");
        return strTime2Timestamp(timestamp, DEFAULT_FORMAT);
    }


    public static void main(String[] args) {
        LocalDate localDate = DateUtils.strDate2LocalDate("2021-12-31T00:00:00+08:00", A2_DATE_FORMAT);
        LocalDate localDate2 = DateUtils.strDate2LocalDate("2022-01-01T00:00:00+08:00", A2_DATE_FORMAT);
        localDate2Str(localDate, "yyyyMMdd");

        String sql = "SELECT * FROM EPDMX.OP_PROD_WELL_PROD_DAILY WHERE WELL_ID = '" + "123456" +
                "' AND PROD_DATE BETWEEN to_date('" + localDate + "', 'yyyy-mm-dd') AND to_date('20171231', 'yyyy-mm-dd')";

        localDate = localDate.plusDays(1);
        System.out.println(localDateIsBefore(localDate, localDate2));

        String timeRegex = "([0-1]?[0-9]|2[0-3]):([0-5][0-9])$";
        boolean s = Pattern.matches(timeRegex, "23:59");
        System.out.println(s);

        try {
            String time = "2021/5/30";
            java.sql.Date sqlTime = strDate2SqlDate(time, EXCEL_DAILY_PROD_FORMAT);
            System.out.println(sqlTime);
        } catch (Exception e) {
            e.printStackTrace();
            throw new IllegalArgumentException(AjaxExceptionEnum.DATE_IS_INVALID.getMsg());
        }

        double tt = 1.115 * 60 * 60;
        String s1 = secToTime((int) tt);
        System.out.println(s1);
        Time time = strTime2SqlTime(s1, EXCEL_CONSTR_TIME_FORMAT);
        System.out.println(time);
    }
}